{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 什么是PyTorch？\n",
    "\n",
    "这是一个基于Python的科学计算包，主要分入如下2部分：\n",
    "\n",
    "- 使用GPU的功能代替numpy\n",
    "- 一个深刻的学习研究平台，提供最大的灵活性和速度\n",
    "\n",
    "## 开始学习\n",
    "### Tensors (张量)\n",
    "Tensors类似于`numpy`的`ndarrays`，另外还可以在GPU上使用`Tensors`来加速计算。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [],
   "source": [
    "from __future__ import print_function\n",
    "import torch"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "构造一个5x3矩阵，不初始化。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([[1.6932e+22, 7.7144e+31, 6.7109e+22],\n",
      "        [1.6486e+22, 4.3605e+27, 2.8929e+12],\n",
      "        [7.5338e+28, 1.8037e+28, 3.4740e-12],\n",
      "        [1.7743e+28, 6.8239e+16, 1.8832e+34],\n",
      "        [1.6078e+19, 4.4721e+21, 5.0789e-11]])\n"
     ]
    }
   ],
   "source": [
    "x = torch.empty(5, 3)\n",
    "print(x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "构造一个随机初始化的矩阵："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([[0.2712, 0.3545, 0.5300],\n",
      "        [0.0976, 0.0149, 0.8799],\n",
      "        [0.7187, 0.7343, 0.4521],\n",
      "        [0.4418, 0.0132, 0.2708],\n",
      "        [0.9201, 0.0794, 0.4476]])\n"
     ]
    }
   ],
   "source": [
    "x = torch.rand(5, 3)\n",
    "print(x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "构造一个矩阵全为 0，而且数据类型是 long."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([[0, 0, 0],\n",
      "        [0, 0, 0],\n",
      "        [0, 0, 0],\n",
      "        [0, 0, 0],\n",
      "        [0, 0, 0]])\n"
     ]
    }
   ],
   "source": [
    "x = torch.zeros(5, 3, dtype=torch.long)\n",
    "print(x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "构造一个张量，直接使用数据："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([5.5000, 3.0000])\n"
     ]
    }
   ],
   "source": [
    "x = torch.tensor([5.5, 3])\n",
    "print(x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "创建一个 tensor 基于已经存在的 tensor。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([[1., 1., 1.],\n",
      "        [1., 1., 1.],\n",
      "        [1., 1., 1.],\n",
      "        [1., 1., 1.],\n",
      "        [1., 1., 1.]], dtype=torch.float64)\n",
      "tensor([[-1.2157, -0.6880,  0.3270],\n",
      "        [-0.3162, -0.2479,  0.8731],\n",
      "        [-0.3330, -0.3823,  0.5237],\n",
      "        [-1.3132, -0.1246,  0.6706],\n",
      "        [ 1.1174, -1.0695,  0.7972]])\n"
     ]
    }
   ],
   "source": [
    "x = x.new_ones(5, 3, dtype=torch.double)     \n",
    "print(x)\n",
    "\n",
    "x = torch.randn_like(x, dtype=torch.float)    \n",
    "print(x)                                     "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "获取它的维度信息:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "torch.Size([5, 3])\n"
     ]
    }
   ],
   "source": [
    "print(x.size())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<div class=\"alert alert-info\"><h4>注意</h4><p>``torch.Size`` 是一个元组，所以它支持左右的元组操作。</p></div>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 操作\n",
    "在接下来的例子中，我们将会看到加法操作。 "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "加法: 方式 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([[-0.4000,  0.0549,  1.2980],\n",
      "        [ 0.0748,  0.5602,  1.2120],\n",
      "        [ 0.1771, -0.1623,  1.4076],\n",
      "        [-0.4690,  0.6656,  0.8570],\n",
      "        [ 1.5434, -0.8243,  1.4676]])\n"
     ]
    }
   ],
   "source": [
    "y = torch.rand(5, 3)\n",
    "print(x + y)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "加法: 方式2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([[-0.4000,  0.0549,  1.2980],\n",
      "        [ 0.0748,  0.5602,  1.2120],\n",
      "        [ 0.1771, -0.1623,  1.4076],\n",
      "        [-0.4690,  0.6656,  0.8570],\n",
      "        [ 1.5434, -0.8243,  1.4676]])\n"
     ]
    }
   ],
   "source": [
    "print(torch.add(x, y))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "加法: 提供一个输出 tensor 作为参数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([[-0.4000,  0.0549,  1.2980],\n",
      "        [ 0.0748,  0.5602,  1.2120],\n",
      "        [ 0.1771, -0.1623,  1.4076],\n",
      "        [-0.4690,  0.6656,  0.8570],\n",
      "        [ 1.5434, -0.8243,  1.4676]])\n"
     ]
    }
   ],
   "source": [
    "result = torch.empty(5, 3)\n",
    "torch.add(x, y, out=result)\n",
    "print(result)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "加法: in-place"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([[-0.4000,  0.0549,  1.2980],\n",
      "        [ 0.0748,  0.5602,  1.2120],\n",
      "        [ 0.1771, -0.1623,  1.4076],\n",
      "        [-0.4690,  0.6656,  0.8570],\n",
      "        [ 1.5434, -0.8243,  1.4676]])\n"
     ]
    }
   ],
   "source": [
    "# adds x to y\n",
    "y.add_(x)\n",
    "print(y)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<div class=\"alert alert-info\"><h4>注意</h4><p>任何使张量会发生变化的操作都有一个前缀 '_'。例如： ``x.copy_(y)``, ``x.t_()``, 将会改变  ``x``.</p></div>\n",
    "\n",
    "你可以使用标准的  NumPy 类似的索引操作"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([-0.6880, -0.2479, -0.3823, -0.1246, -1.0695])\n"
     ]
    }
   ],
   "source": [
    "print(x[:, 1])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "改变大小：如果你想改变一个 tensor 的大小或者形状，你可以使用 `torch.view`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "torch.Size([4, 4]) torch.Size([16]) torch.Size([2, 8])\n"
     ]
    }
   ],
   "source": [
    "x = torch.randn(4, 4)\n",
    "y = x.view(16)\n",
    "z = x.view(-1, 8)  # the size -1 is inferred from other dimensions\n",
    "print(x.size(), y.size(), z.size())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "如果你有一个元素 `tensor` ，可以使用 `.item()` 来获得这个 `tensor` 的值 。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([-0.4592])\n",
      "-0.4592222571372986\n"
     ]
    }
   ],
   "source": [
    "x = torch.randn(1)\n",
    "print(x)\n",
    "print(x.item())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Numpy转换\n",
    "将Tensor转换为numpy数组"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([1., 1., 1., 1., 1.])\n"
     ]
    }
   ],
   "source": [
    "a = torch.ones(5)\n",
    "print(a)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1. 1. 1. 1. 1.]\n"
     ]
    }
   ],
   "source": [
    "b = a.numpy()\n",
    "print(b)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "看看numpy数组的值如何变化。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([2., 2., 2., 2., 2.])\n",
      "[2. 2. 2. 2. 2.]\n"
     ]
    }
   ],
   "source": [
    "a.add_(1)\n",
    "print(a)\n",
    "print(b)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "将 `numpy` 数组转换为`Torch`张量"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[2. 2. 2. 2. 2.]\n",
      "tensor([2., 2., 2., 2., 2.], dtype=torch.float64)\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "a = np.ones(5)\n",
    "b = torch.from_numpy(a)\n",
    "np.add(a, 1, out=a)\n",
    "print(a)\n",
    "print(b)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "除了 `CharTensor` ,CPU 上的所有 `Tensors` 与 `NumPy` 都可以相互转化\n",
    "\n",
    "## CUDA Tensors\n",
    "\n",
    "可以通过 `.to` 方法将 `Tensors` 转移到任何设备"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([0.5408], device='cuda:0')\n",
      "tensor([0.5408], dtype=torch.float64)\n"
     ]
    }
   ],
   "source": [
    "# 在GPU可用时运行\n",
    "# 我们将使用 torch.device 对象将 tensors 移入、移出GPU\n",
    "if torch.cuda.is_available():\n",
    "    device = torch.device(\"cuda\")          # 创建一共 CUDA设备对象\n",
    "    y = torch.ones_like(x, device=device)  # 在GPU上直接创建一个 tensor\n",
    "    x = x.to(device)                       # 等价于：x = x.to(\"cuda\")\n",
    "    z = x + y\n",
    "    print(z)\n",
    "    print(z.to(\"cpu\", torch.double))       # .to() 将同时改变数据类型"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.8rc1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
